﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Text;
using System.IO;
using System.Xml;
using _7DaysToDieTools;
using System.Text.RegularExpressions;
using Mono.Cecil;
using Mono.Cecil.Cil;
using System.Threading;
using System.Windows.Forms;

namespace _7DaysToDieTools.Class
{
    /// <summary>
    /// 语言操作类
    /// </summary>
    public static class LangAction
    {
        /// <summary>
        /// 检测字符串是否含有中文
        /// </summary>
        /// <param name="str"></param>
        /// <returns></returns>
        private static bool HasChinese(string str)
        {
            return Regex.IsMatch(str, @"[\u4e00-\u9fa5]");
        }

        /// <summary>
        /// 加载语言字段列表
        /// </summary>
        /// <param name="FilePath">语言文件路径</param>
        /// <returns>LangItem列表</returns>
        public static List<LangItem> LoadLangData(string FilePath)
        {
            List<LangItem> LangItems = new List<LangItem>();
            LangItem li = null;
            using(CsvFileReader CFR=new CsvFileReader(FilePath))
            {
                CsvRow cr = new CsvRow();
                CFR.ReadRow(cr);//过滤第一行标题
                while (CFR.ReadRow(cr))
                {
                    if (cr == null) continue;
                    //检测重复,并优化应用汉化(自前向后原则)
                    LangItem tmpLi = LangItems.Find(X => X.Key == cr[0].ToString());
                    if (tmpLi != null)
                    {
                        if (HasChinese(tmpLi.English)) continue;
                        tmpLi.English = cr[4].ToString();
                        continue;
                    }
                    li = new LangItem();
                    li.Key = cr[0].ToString();
                    li.Source = cr[1].ToString();
                    li.Context = cr[2].ToString();
                    li.Changes = cr[3].ToString();
                    li.English = cr[4].ToString();
                    if (cr.Count <= 5)
                    {
                        li.French = "";
                    }
                    else
                    {
                        li.French = cr[5].ToString();
                    }
                    
                    if (cr.Count <= 6)
                    {
                        li.German = "";
                    }
                    else
                    {
                        li.German = cr[6].ToString();
                    }
                    if (cr.Count <= 7)
                    {
                        li.Klingon = "";
                    }
                    else
                    {
                        li.Klingon = cr[7].ToString();
                    }

                    if (cr.Count <= 8)
                    {
                        li.Spanish = "";
                    }
                    else
                    {
                        li.Spanish = cr[8].ToString();
                    }

                    LangItems.Add(li);
                }
            }
            return LangItems;
        }

        /// <summary>
        /// 保存语言字段列表
        /// </summary>
        /// <param name="listLangs">语言字段列表</param>
        /// <returns></returns>
        public static void SaveLangData(List<LangItem> listLangs)
        {
            try
            {
                FileStream fs = new FileStream(Sinfo.Path.Lang + Sinfo.File.Localization, FileMode.Create);
                StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
                //添加第一行的头
                sw.WriteLine(LangItem.GetHeader());
                //添加数据
                for (int i = 0; i < listLangs.Count; i++)
                {
                    sw.WriteLine(listLangs[i].ToStr());
                }
                sw.Close();
                fs.Close();
            }
            catch(Exception x)
            {
                throw new Exception("保存出错:" + x.Message, x);
            }
        }

        /// <summary>
        /// 更改游戏内部字体支持中文
        /// </summary>
        /// <param name="Msg">返回信息</param>
        /// <returns></returns>
        public static bool ChangeFontToChinese(out String Msg)
        {
            Msg = "";
            try
            {
                DirectoryInfo tmp = new DirectoryInfo(Sinfo.Path.XUi);
                if (!tmp.Exists)
                {
                    Msg = "找不到路径：" + Sinfo.Path.XUi;
                    return false;
                }
                FileInfo fi = new FileInfo(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                if (!tmp.Exists)
                {
                    Msg = "找不到设置字体的文件：" + Sinfo.Path.XUi + Sinfo.File.XuiStyle;
                    return false;
                }
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                XmlElement xe = xDoc.SelectSingleNode(@"/styles/style[@type='label']/style_entry[@name='font_face']") as XmlElement;
                xe.SetAttribute("value", "AgencyB");
                xDoc.Save(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                return true;
            }
            catch (Exception x)
            {
                Msg = x.Message;
                return false;
            }
        }

        /// <summary>
        /// 更改游戏内部字体为默认
        /// </summary>
        /// <param name="Msg">返回信息</param>
        /// <returns></returns>
        public static bool ChangeFontToDefault(out String Msg)
        {
            Msg = "";
            try
            {
                DirectoryInfo tmp = new DirectoryInfo(Sinfo.Path.XUi);
                if (!tmp.Exists)
                {
                    Msg = "找不到路径：" + Sinfo.Path.XUi;
                    return false;
                }
                FileInfo fi = new FileInfo(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                if (!tmp.Exists)
                {
                    Msg = "找不到设置字体的文件：" + Sinfo.Path.XUi + Sinfo.File.XuiStyle;
                    return false;
                }
                XmlDocument xDoc = new XmlDocument();
                xDoc.Load(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                XmlElement xe = xDoc.SelectSingleNode(@"/styles/style[@type='label']/style_entry[@name='font_face']") as XmlElement;
                xe.SetAttribute("value", "AgencyB_32p");
                xDoc.Save(Sinfo.Path.XUi + Sinfo.File.XuiStyle);
                return true;
            }
            catch (Exception x)
            {
                Msg = x.Message;
                return false;
            }
        }

        /// <summary>
        /// 以指定文件的字段，替换指定语言文件内的同名字段。
        /// </summary>
        /// <param name="SLangFilePath">源语言文件路径</param>
        /// <param name="DLangFilePath">要替换的语言文件路径</param>
        /// <param name="ReplaceHan">是否替换目标语言文件已汉化字段</param>
        /// <returns></returns>
        public static void ApplyLangItems(string SLangFilePath,string DLangFilePath,bool ReplaceHan)
        {
            try
            {
                CsvFileReader CFR = null;
                string tmp = "";
                // 获取源字段字典
                Dictionary<string, string> SLangItems = new Dictionary<string, string>();
                using (CFR = new CsvFileReader(SLangFilePath))
                {
                    CsvRow cr = new CsvRow();
                    CFR.ReadRow(cr);//过滤第一行标题
                    while (CFR.ReadRow(cr))
                    {
                        SLangItems.Add(cr[0], cr[4]);
                    }
                }
                //替换
                List<LangItem> DLangItems = LoadLangData(DLangFilePath);
                foreach (LangItem item in DLangItems)
                {
                    if (SLangItems.TryGetValue(item.Key, out tmp))
                    {
                        if (HasChinese(tmp))
                        {
                            if (HasChinese(item.English))
                            {
                                if (ReplaceHan)
                                {
                                    item.English = tmp;
                                }
                            }
                            else
                            {
                                item.English = tmp;
                            }
                        }
                    }
                }
                //保存
                FileStream fs = new FileStream(DLangFilePath, FileMode.Create);
                StreamWriter sw = new StreamWriter(fs, new UTF8Encoding(false));
                //添加第一行的头
                sw.WriteLine(LangItem.GetHeader());
                //添加数据
                for (int i = 0; i < DLangItems.Count; i++)
                {
                    sw.WriteLine(DLangItems[i].ToStr());
                }
                sw.Close();
                fs.Close();
            }
            catch(Exception x)
            {
                throw new Exception("替换字段时出错:\n" + x.Message, x);
            }
        }

        /// <summary>
        /// 添加主菜单支持中文DLL
        /// </summary>
        /// <param name="dllPath">Dll路径</param>
        /// <returns></returns>
        [Obsolete("新的汉化不要修改DLL",true)]
        public static void DllAddChina(string dllPath)
        {
            DefaultAssemblyResolver dar = new DefaultAssemblyResolver();
            dar.AddSearchDirectory(new DirectoryInfo(dllPath).Parent.FullName);
            ModuleDefinition MD = null;
            ModuleDefinition MDNew = null;
            try
            {
                MD = ModuleDefinition.ReadModule(dllPath, new ReaderParameters { AssemblyResolver = dar });
                MDNew = ModuleDefinition.ReadModule(new DirectoryInfo(dllPath).Parent.FullName + "\\DaysToDie.dll", new ReaderParameters { AssemblyResolver = dar });
            }
            catch
            {
                throw new Exception("无法调用要修改的DLL");
            }

            //添加DaysToDie引用
            if (MD.AssemblyReferences.FirstOrDefault(O => O.Name == "DaysToDie") == null)
            {
                MD.AssemblyReferences.Add(new AssemblyNameReference("DaysToDie", new Version(0, 0, 0, 0)));
            }
            if (MD.Types.FirstOrDefault(o => o.Name == "SplashScreenScript").Methods.FirstOrDefault(m => m.Name == "Awake").Body.Instructions.FirstOrDefault(I => I.OpCode == OpCodes.Call & I.Offset == 1) == null)
            {
                var nm = MD.Import(MDNew.Types.FirstOrDefault(o => o.FullName == "YLY.Doit").Methods.FirstOrDefault(M => M.Name == "GKeysObj"));

                //添加方法调用 SplashScreenScript-Awake
                MD.Types.FirstOrDefault(o => o.Name == "SplashScreenScript").Methods.FirstOrDefault(m => m.Name == "Awake").Body.Instructions.Insert(1, Instruction.Create(OpCodes.Call, nm));
            }
            MD.Write(dllPath);
        }

        /// <summary>
        /// 获取指定语言名称的数据包文件名
        /// </summary>
        /// <param name="LangName">语言名称</param>
        /// <returns></returns>
        public static string GetLangFile(string LangName)
        {
            NetConfig.GetConfig(true);
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(Sinfo.Data.BasePath + Sinfo.Net.File.Config);
            XmlElement xe = xDoc.SelectSingleNode("/config/langs//lang[@name='" + LangName + "']") as XmlElement;
            if (xe == null) return "";
            return xe.InnerText;
        }

        /// <summary>
        /// 初始化汉化选择列表
        /// </summary>
        /// <param name="cbox">汉化选择框</param>
        public static void LoadLangList(ComboBox cbox)
        {
            cbox.Items.Clear();
            cbox.Items.Add("[本地]完美汉化(调用游乐园汉化补丁)");
            cbox.Items.Add("[网络]完美汉化(使用游乐园汉化补丁)");
            
        }

        /// <summary>
        /// 应用修改方式的完美汉化
        /// </summary>
        public static void ApplyLangNet()
        {
            try
            {
                //获取文件名
                string fileName = GetLangFile("游乐园汉化");
                //下载文件
                List<string> listFiles = new List<string>();
                listFiles.Add(Sinfo.Net.Lang + fileName);
                new FormDown(null, listFiles).ShowDialog();
                //移动文件
                if (!Directory.Exists(Sinfo.Data.Lang))
                {
                    Directory.CreateDirectory(Sinfo.Data.Lang);
                }
                if (File.Exists(Sinfo.Data.Lang + fileName))
                {
                    File.Delete(Sinfo.Data.Lang + fileName);
                }
                File.Move(Sinfo.Data.BasePath + fileName, Sinfo.Data.Lang + fileName);
                //解压文件
                using (FileStream fs = File.Open(Sinfo.Data.Lang + fileName, FileMode.Open))
                {
                    ZipAction.UnzipDatas(fs, Sinfo.Data.Lang);
                }
                if (!File.Exists(Sinfo.Data.Lang + fileName)) throw new Exception("找不到汉化所需的文件！");
                using (FileStream fs = File.Open(Sinfo.Data.Lang + fileName, FileMode.Open))
                {
                    ZipAction.UnzipDatas(fs, Sinfo.Data.Lang);
                }
                //修改资源文件
                Directory.Move(Sinfo.Data.Lang + "7DaysToDie_Data\\resources_unpak", Sinfo.Path.Data + "resources_unpak");
                Directory.Move(Sinfo.Data.Lang + "7DaysToDie_Data\\sharedassets1_unpak", Sinfo.Path.Data + "sharedassets1_unpak");
                ProcessStartInfo psi = new ProcessStartInfo(Sinfo.Path.Data + "resources_unpak\\yly.exe");
                psi.WorkingDirectory = Sinfo.Path.Data + "resources_unpak";
                psi.Arguments = "-i ..\\resources.assets";
                Process.Start(psi).WaitForExit(10000);
                psi.Arguments = "-i ..\\sharedassets1.assets";
                Process.Start(psi).WaitForExit(10000);

                //删除以上资源文件
                Directory.Delete(Sinfo.Path.Data + "resources_unpak", true);
                Directory.Delete(Sinfo.Path.Data + "sharedassets1_unpak", true);
                //替换Localization.txt字段
                ApplyLangItems(Sinfo.Data.Lang + "Data\\Config\\" + Sinfo.File.Localization, Sinfo.Path.Lang + Sinfo.File.Localization, true);
                //替换Localization - Quest.txt字段
                ApplyLangItems(Sinfo.Data.Lang + "Data\\Config\\" + Sinfo.File.LocalizationQuest, Sinfo.Path.Lang + Sinfo.File.LocalizationQuest, true);
                //controls.xml
                KeyAddControls();
                //windows.xml
                KeyAddWindows();

                //删除所有资源
                Directory.Delete(Sinfo.Data.Lang,true);
            }
            catch(Exception x)
            {
                throw new Exception("应用汉化出错:\n" + x.Message, x);
            }

        }

        /// <summary>
        /// 应用覆盖方式的完美汉化
        /// </summary>
        public static void ApplyLangLocal()
        {
            try
            {
                string fileName = "A15B105Lang.exe";
                File.WriteAllBytes(Sinfo.PathCurr + fileName, Files.A15B105Lang);
                ProcessStartInfo psi = new ProcessStartInfo(Sinfo.PathCurr + fileName);
                psi.WorkingDirectory = Sinfo.PathCurr;
                Process.Start(psi).WaitForExit(60000);
            }
            catch(Exception x)
            {
                throw new Exception("应用本地完美汉化出错：\n" + x.Message, x);
            }
        }

        /// <summary>
        /// 添加controls.xml中的缺少的key。并同步到Localization.txt
        /// </summary>
        public static void KeyAddControls()
        {
            string file = Sinfo.Path.XUi + Sinfo.File.XuiControls;
            List<LangItem> listLang = LoadLangData(Sinfo.Path.Lang + Sinfo.File.Localization);
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(file);
            //xuiITEM
            KeyAddLang("/controls/ingredient_header/rect/rect/label[@text='ITEM']", "text_key", "xuiITEM", "物品", xDoc, listLang);
            //xuiNAME
            KeyAddLang("/controls/ingredient_header/rect/rect/label[@text='NAME']", "text_key", "xuiNAME", "名称", xDoc, listLang);
            //xuiNEED
            KeyAddLang("/controls/ingredient_header/rect/rect/label[@text='NEED']", "text_key", "xuiNEED", "需要", xDoc, listLang);
            //xuiHAVE
            KeyAddLang("/controls/ingredient_header/rect/rect/label[@text='HAVE']", "text_key", "xuiHAVE", "拥有", xDoc, listLang);
            //xuiNAME
            KeyAddLang("/controls/waypoint_entry/rect/label[@text='NAME']", "text_key", "xuiNAME", "名称", xDoc, listLang);
            //xuiNAME
            KeyAddLang("/controls/invites_entry/rect/label[@text='NAME']", "text_key", "xuiNAME", "名称", xDoc, listLang);
            //xuiSHOW
            KeyAddLang("/controls/players_entry/rect/rect/label[@name='labelShowOnMap']", "text_key", "xuiSHOW", "显示", xDoc, listLang);
            
            xDoc.Save(file);
            SaveLangData(listLang);
        }

        /// <summary>
        /// 添加windows.xml中的缺少的key。并同步到Localization.txt
        /// </summary>
        public static void KeyAddWindows()
        {
            string file = Sinfo.Path.XUi + Sinfo.File.XuiWindows;
            List<LangItem> listLang = LoadLangData(Sinfo.Path.Lang + Sinfo.File.Localization);
            XmlDocument xDoc = new XmlDocument();
            xDoc.Load(file);
            //---------------------------------------------------------------------------------------
            //windowCreative
            KeyAddLang("/windows/window[@name='windowCreative']/rect/button[@name='all']", "tooltip_key", "lblAll", "全部", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowCreative']/rect/button[@name='items']", "tooltip_key", "lblAllItems", "全部物品", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowCreative']/rect/button[@name='simplepickup']", "tooltip_key", "lblSimplePickup", "简单拾取", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowCreative']/rect/button[@name='devblocks']", "tooltip_key", "lblDevBlocks", "开发方块", xDoc, listLang);
            //windowSkillInfo
            KeyAddLang("/windows/window[@name='windowSkillInfo']/rect[@name='content']/rect/label[@name='XpToNextLevel']", "text_key", "xuiXpToNextLevel", "升级所需经验：", xDoc, listLang);
            //windowArchetypePreview2
            KeyAddLang("/windows/window[@name='windowArchetypePreview2']/panel[@name='header']/label[@text='PREVIEW']", "text_key", "xuiPreview", "预览", xDoc, listLang);
            //windowArchetypeList
            KeyAddLang("/windows/window[@name='windowArchetypeList']/panel[@name='header']/label[@text='ARCHETYPES']", "text_key", "xuiArchetypes", "原型", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowArchetypeList']/panel[@name='buttonContent']/rect/label[@text='SAVE']", "text_key", "xuiSave", "保存", xDoc, listLang);
            //windowClothingList
            KeyAddLang("/windows/window[@name='windowClothingList']/panel[@name='header']/label[@text='CLOTHING']", "text_key", "xuiClothing", "服装", xDoc, listLang);
            //windowSliders
            KeyAddLang("/windows/window[@name='windowSliders']/panel[@name='header']/label[@text='DNA SLIDERS']", "text_key", "xuiDnaSliders", "DNA 滑块", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowSliders']/panel[@name='buttonContent']/rect/label[@text='SAVE']", "text_key", "xuiSAVE", "保存", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowSliders']/panel[@name='buttonContent']/rect/label[@text='CANCEL']", "text_key", "xuiCANCEL", "取消", xDoc, listLang);
            //windowColorPicker
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='buttonContent']/label[@text='Slots and Layers']", "text_key", "xuiSlotsAndLayers", "槽位和层", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='content']/rect[@name='slotSelector']/label[@name='slotLabel']", "text_key", "xuiSlot", "槽位：", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='content']/rect[@name='layerSelector']/label[@name='slotLabel']", "text_key", "xuiLayer", "层：", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='content']/rect[@name='overlaySelector']/label[@name='slotLabel']", "text_key", "xuiOverlayIndex", "层数：", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='content']/rect/label[@text='Slot Name:']", "text_key", "xuiSlotName", "槽位名：", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowColorPicker']/panel[@name='content']/rect/label[@text='Overlay Name:']", "text_key", "xuiOverlayName", "层名：", xDoc, listLang);
            //windowSignEdit
            KeyAddLang("/windows/window[@name='windowSignEdit']/panel[@name='header']/label[@text='SIGN']", "text_key", "xuiSIGN", "记号", xDoc, listLang);
            //windowRWGPreview
            KeyAddLang("/windows/window[@name='windowRWGPreview']/panel[@name='header']/label[@text='RANDOM GEN WORLD PREVIEWER']", "text_key", "xuiRandomGenWorldPreviewer", "随机世界预览", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowRWGPreview']/panel/label[@name='Startup']", "text_key", "xuiStartup", "请点击刷新或是点击输入种子或是地图尺寸", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowRWGPreview']/panel/label[@name='Startup2']", "text_key", "xuiStartup2", "生成地图数据也许需要两分钟时间", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowRWGPreview']/panel/rect/recipe_search[@name='worldSizeInput']", "tooltip_key", "lblWorldSizeInput", "尺寸(1-5)", xDoc, listLang);
            KeyAddLang("/windows/window[@name='windowRWGPreview']/panel/rect/label[@name='TextContent']", "text_key", "xuiTextContent", "尺寸(1-5)", xDoc, listLang);
            //---------------------------------------------------------------------------------------
            xDoc.Save(file);
            SaveLangData(listLang);
        }

        /// <summary>
        /// 添加信息到xml文件与langItem列表
        /// </summary>
        /// <param name="xPath">xml的xpath</param>
        /// <param name="nameKey">要添加的text_key或者tooltip_key</param>
        /// <param name="valueKey">nameKey的变量值</param>
        /// <param name="valueLang">valueKey对应的汉化</param>
        /// <param name="xDoc">xmlDocument</param>
        /// <param name="listLangs">list langitem</param>
        public static void KeyAddLang(string xPath,string nameKey,string valueKey,string valueLang,XmlDocument xDoc,List<LangItem> listLangs)
        {
            XmlElement xe = xDoc.SelectSingleNode(xPath) as XmlElement;
            XmlAttribute xa = null;
            if (xe != null)
            {
                if (!xe.HasAttribute(nameKey))
                {
                    xa = xDoc.CreateAttribute(nameKey);
                    xa.Value = valueKey;
                    xe.Attributes.Append(xa);
                }
            }
            if (listLangs.Where(X => X.Key == valueKey).Count() == 0)
            {
                LangItem li = new LangItem();
                li.Key = valueKey; li.Source = "UI";
                if (nameKey == "text_key")
                {
                    li.Context = "XUI";
                }
                else if (nameKey == "tooltip_key")
                {
                    li.Context = "Tooltip";
                }
                li.Changes = "KgNone";
                li.English = valueLang; li.French = ""; li.German = ""; li.Klingon = ""; li.Spanish = "";
                listLangs.Add(li);
            }
        }
    }
}
